package com.ahdms.es.engine;

import com.ahdms.es.bean.SealInfo;
import com.ahdms.es.bean.SesSignInfo;
import com.ahdms.es.bean.enums.ApiCode;
import com.ahdms.es.exceptions.*;
import com.ahdms.es.gm.v4.SES_Signature;
import com.ahdms.es.gm.v4.TBS_Sign;
import com.ahdms.es.result.VerifyResult;
import com.ahdms.es.util.DataConvert;
import com.ahdms.es.util.DateUtils;
import org.bouncycastle.asn1.x509.Certificate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
import java.util.Optional;

/**
 * 国标格式的电子签章数据验证
 *
 * @author qinxiang
 * @date 2021-04-09 11:27
 */
public class SesSignatureGBVerifyEngine extends SesSignatureVerifyEngine {
    private static final Logger log = LoggerFactory.getLogger(SesSignatureGBVerifyEngine.class);

    private SesSignInfo sesSignInfo;

    private final Certificate signCert;

    private final SES_Signature sesSignature;

    public SesSignatureGBVerifyEngine(byte[] sesSignatureData) {
        this.sesSignature = SES_Signature.getInstance(sesSignatureData);
        this.signCert = Certificate.getInstance(this.sesSignature.getCert().getOctets());
//        this.sesSignInfo = new SesSignInfo(DataConvert.toSealInfo(sesSignature.getToSign().getEseal()),DataConvert.certToCertInfo(this.signCert));
    }

    public SesSignatureGBVerifyEngine(SES_Signature sesSignature) {
        this.sesSignature = sesSignature;
        this.signCert = Certificate.getInstance(this.sesSignature.getCert().getOctets());
//        this.sesSignInfo = new SesSignInfo(DataConvert.toSealInfo(sesSignature.getToSign().getEseal()),DataConvert.certToCertInfo(this.signCert));
    }

    public static SesSignatureGBVerifyEngine getInstance(byte[] sesSignatureData) throws VerifySesSignException {
        try {
            if (sesSignatureData != null) {
                return new SesSignatureGBVerifyEngine(sesSignatureData);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw new VerifySesSignException(ApiCode.SESIGN_FORMART_FAIL);
    }

    @Override
    public void verifySignData() throws IOException, VerifySesSignException {
        String signatureAlgorithmId = sesSignature.getSignatureAlgID().getId();
        byte[] srcData = sesSignature.getToSign().getEncoded();
        byte[] signValue = sesSignature.getSignature().getOctets();
        verifySignData(signCert, signatureAlgorithmId, srcData, signValue);
    }

    @Override
    public void verifySeSeal() throws VerifySesSignException {
        VerifyResult<SealInfo> verify = SeSealVerifyEngine.verify(sesSignature.getToSign().getEseal());
        if(!verify.isResult()){
            log.error("电子印章验证失败..{}",verify.getErrorMsg());
            throw new VerifySesSignException(ApiCode.SESIGN_VERIFY_Seal_Fail);
        }
    }

    @Override
    public Certificate getSignCert() {
        return this.signCert;
    }

    @Override
    public Date getRevokeDate() {
        return revokeDate;
    }

    @Override
    public Date getSignDate() {
        return Optional.ofNullable(sesSignature).map(SES_Signature::getToSign)
                .map(TBS_Sign::getTimeInfo)
                .map(asn1GeneralizedTime -> {
                    try {
                        return asn1GeneralizedTime.getDate();
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    return null;
                })
                .orElseThrow(() -> new ApiException("签章时间解析失败"));
    }

    @Override
    public byte[] getSesDataHash() {
        return sesSignature.getToSign().getDataHash().getBytes();
    }

    @Override
    public SesSignInfo getSesSignInfo(){
        return SesSignInfo.builder().signDate(DateUtils.format(getSignDate()))
                .sealInfo(DataConvert.toSealInfo(sesSignature.getToSign().getEseal()))
                .certInfo(DataConvert.certToCertInfo(this.signCert))
                .build();
    }
}
